#pragma once

struct TOctree;

// the base interface for both node and leaf
struct TOctreeNodeInterface
{
	bool empty;
	AABB aabb;

	// AABB that contains the actual triangles
	AABB triangleAABB;
	// True if the triangleAABB is fully contained by aabb
	bool bIsTriangleAABBSmaller;

	// initialize a node
	virtual void Init(TOctree* tree, AABB& _aabb, int curdepth) = 0;

	// push a triangle into the octree
	virtual void PushTriangle(int triIndex, TCRTVertexMini v[3]) = 0;

	// update the triangleAABB value
	virtual void UpdateTriangleAABB(TOctree* pTree) = 0;

	// hit a ray against the node, it's already been checked against current node's aabb
	virtual bool RayIntersect(TOctree* tree) = 0;
};

struct TOctreeNode : TOctreeNodeInterface
{
	TOctreeNodeInterface* child[8];

	virtual void Init(TOctree* tree, AABB& _aabb, int curdepth);
	virtual void PushTriangle(int triIndex, TCRTVertexMini v[3]);
	virtual void UpdateTriangleAABB(TOctree* pTree);
	virtual bool RayIntersect(TOctree* tree);
};

struct TOctreeLeaf : TOctreeNodeInterface
{
	std::vector<int> triangles;	// index into mesh's triangles array

	virtual void Init(TOctree* /*tree*/, AABB& /*_aabb*/, int /*curdepth*/) {}
	virtual void PushTriangle(int triIndex, TCRTVertexMini v[3]);
	virtual void UpdateTriangleAABB(TOctree* pTree);
	virtual bool RayIntersect(TOctree* tree);
};


enum IntersectTestType
{
	ITT_StopOnHit = 0,
	ITT_NearestHit, 
	ITT_AllHits, 

	ITT_Num,
};

// the octree, we'll use it to manage a TCRTMesh
struct TOctree
{
	TOctreeNodeInterface* root;
	int depth;
	int nnode;
	int nleaf;	

	// the referenced mesh
	TCRTMesh* mesh;

	// current node/leaf, used for allocation
	TOctreeNode* _curnode;
	TOctreeLeaf* _curleaf;
	
	// data for ray intersection test
	vector<TSceneIntersection>* RI_info;
	IntersectTestType RI_type;
	RAY* RI_ray;
	int  RI_nrayaabb;		// stat for ray-aabb intersection testing
	int  RI_nraytriangle;	// stat for ray-triangle intersection testing
	double RI_raytritime;	// stat for ray-triangle intersection testing
	TCRTTriangleHelper* RI_testedHelper;

	TOctree(struct TCRTMesh* inmesh);
	~TOctree();

	void ResetStat() { RI_nrayaabb = 0; RI_nraytriangle = 0; RI_raytritime = 0; }

	// If type == ITT_StopOnHit or ITT_NearestHit, please make sure one intesection info is all provided in the info array
	bool RayIntersect(RAY* ray, vector<TSceneIntersection>& info, IntersectTestType type);

protected :

	// the allocated data
	TOctreeNode* _node;
	TOctreeLeaf* _leaf;
};